import { Component, OnInit } from "@angular/core";
import { BehaviorSubject, Subject, Observable, of as observableOf } from "rxjs";
import { MenuItemModel, AuthService } from "src/app/core/auth/auth.service";
import { takeUntil } from "rxjs/operators";
import * as fp from "lodash/fp";
import { FetchService } from "src/app/core/net/fetch.service";
import { UtilService } from "src/app/core/util/util.service";
import {
  NzMessageService,
  NzModalService,
  NzFormatEmitEvent,
  NzTreeNode
} from "ng-zorro-antd";
import {
  FormGroup,
  FormBuilder,
  FormControl,
  Validators
} from "@angular/forms";

@Component({
  selector: "app-menu-manage",
  templateUrl: "./menu-manage.component.html",
  styleUrls: ["./menu-manage.component.scss"]
})
export class MenuManageComponent implements OnInit {
  treeDataChange = new BehaviorSubject<MenuItemModel[]>([]);
  unsubscribe: Subject<void> = new Subject<void>();
  hasChanges: boolean = false;

  dataSource;
  menuList: Array<MenuItemModel>;
  menuPathList: Array<TreePath>;

  searchValue: string = "";
  activedNode: NzTreeNode;
  selectedItem: any = {};

  form: FormGroup;

  constructor(
    private fetchService: FetchService,
    private utilService: UtilService,
    private authService: AuthService,
    private message: NzMessageService,
    private modalService: NzModalService,
    private fb: FormBuilder
  ) {}

  ngOnInit() {
    this.treeDataChange.pipe(takeUntil(this.unsubscribe)).subscribe(data => {
      this.getTreeData(data);
      this.dataSource = data;
      // console.log(this.dataSource);

      // 生成父级菜单名
      this.buildNamePath("", data);
    });

    this.fetchMenuList();

    this.form = this.fb.group({
      // 初始化表单
      id: undefined,
      name: "",
      parentId: "",
      href: "",
      icon: "",
      sort: new FormControl(0, [Validators.required]),
      isIconMenu: false
    });

    this.form.controls["parentId"].valueChanges
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(value => {
        this.updateIconMenuCheckStatus(value, this.form.value.icon);
      });

    this.form.controls["icon"].valueChanges
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(value => {
        this.updateIconMenuCheckStatus(this.form.value.parentId, value);
      });
  }

  getTreeData(data) {
    data.sort((a, b) => {
      return a.sort - b.sort;
    });
    data.map(item => {
      item.title = item.name;
      item.key = item.id;
      if (item.id == "0") {
        item.expanded = true;
      }
      if (item.children && item.children.length) {
        this.getTreeData(item.children);
      } else {
        item.isLeaf = true;
      }
    });
  }

  private fetchMenuList(force?: boolean): void {
    if (force || !this.menuList) {
      this.fetchService
        .post<any>("sys/sysMenu/list", { pageSize: 500 })
        .pipe(takeUntil(this.unsubscribe))
        .subscribe(res => {
          res.list.unshift({ id: "0", name: "菜单", parentIds: "" });
          this.menuList = res.list;
          this.utilService
            .flat2Nested<MenuItemModel>(res.list, {
              pathProperty: "parentIds",
              rootId: "0"
            })
            .subscribe(data => {
              this.treeDataChange.next([data]);
            });
        });
    }
  }

  /**
   * 依据关键字过滤菜单树
   * @param keyword 关键字
   */
  filterTree(keyword): void {
    if (!keyword) {
      return;
    }
    let idxList = [];
    let menuList = fp.cloneDeep(this.menuList) || [];
    // 筛选搜索结果
    const newList = menuList.filter(item => item.name.indexOf(keyword) > -1);

    newList.forEach(item => {
      // 获取parentId
      idxList = idxList.concat(item.parentIds.split(","));
      idxList.push(item.id);
    });
    idxList = Array.from(new Set(idxList)); // 去重

    menuList = menuList.filter(item => idxList.indexOf(item.id) > -1);

    this.utilService
      .flat2Nested<MenuItemModel>(menuList, {
        pathProperty: "parentIds",
        rootId: "0"
      })
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(
        res => {
          this.treeDataChange.next([res]);
        },
        () => {
          this.message.warning("无法检索到指定菜单");
          this.treeDataChange.next([]);
        }
      );
  }

  /**
   * 依据菜单树数据递归遍历构建菜单名列表
   * @param {string} namePrefix
   * @param {Array<MenuItemModel>} menuList
   */
  buildNamePath(namePrefix: string, menuList: Array<MenuItemModel>) {
    if (namePrefix == "") {
      this.menuPathList = [];
    }
    const separator = "/";
    menuList.forEach(menu => {
      const namePath = namePrefix + menu.name;
      this.menuPathList.push({ id: menu.id, namePath });
      if (menu.children && menu.children.length > 0) {
        this.buildNamePath(namePath + separator, menu.children);
      }
    });
  }

  checkChanges(): Observable<boolean> {
    if (this.hasChanges) {
      this.modalService.confirm({
        nzTitle: "有未保存信息",
        nzContent:
          "监测到存在未提交信息，如果继续则修改信息将丢失。<br/>确认继续？",
        nzOnOk: () => {
          return observableOf(true);
        }
      });
    }
    return observableOf(true);
  }

  // 查看
  checkDetail(data: NzFormatEmitEvent) {
    this.activedNode = data.node!;
    const item = data.node.origin;
    this.checkChanges().subscribe(res => {
      if (res) {
        const detail =
          item.id != "0"
            ? fp.assign(item, { isIconMenu: item.type == "2" })
            : {};
        this.form.disable();
        this.form.reset(detail);
        this.selectedItem = item;
        this.hasChanges = false;
      }
    });
  }

  // 编辑
  editNode(item, event) {
    event.stopPropagation();
    this.checkChanges().subscribe(res => {
      if (res) {
        this.form.reset(fp.assign(item, { isIconMenu: item.type == "2" }));
        this.form.enable();
        this.form.valueChanges
          .pipe(takeUntil(this.unsubscribe))
          .subscribe(() => {
            this.hasChanges = true;
          });
        this.selectedItem = item;
        this.hasChanges = false;
      }
    });
  }

  // 添加菜单
  addNode(item, event) {
    event.stopPropagation();
    this.checkChanges().subscribe(res => {
      if (res) {
        this.form.reset({ parentId: item.id, isIconMenu: false });
        this.form.enable();
        this.form.valueChanges
          .pipe(takeUntil(this.unsubscribe))
          .subscribe(() => {
            this.hasChanges = true;
          });
        this.selectedItem = undefined;
        this.hasChanges = false;
      }
    });
  }

  // 删除节点
  deleteNode(item, event) {
    event.stopPropagation();
    this.checkChanges().subscribe(res => {
      if (res) {
        this.modalService.confirm({
          nzTitle: "确认删除",
          nzContent: "确认删除此项吗？",
          nzOnOk: () => {
            this.fetchService
              .post("sys/sysMenu/edit", fp.assign(item, { delFlag: "1" }))
              .subscribe(data => {
                this.updateMenu();
                if (this.selectedItem == item) {
                  this.selectedItem = null;
                  this.form.reset();
                }
              });
          }
        });
        this.hasChanges = false;
      }
    });
  }

  // 重置表单
  resetForm() {
    const data = this.selectedItem
      ? fp.assign(this.selectedItem, {
          isIconMenu: this.selectedItem.type == "2"
        })
      : {};
    this.form.reset(data);
    this.hasChanges = false;
  }

  // 提交表单
  submitForm(form) {
    if (!form.valid) {
      this.message.warning("信息填写有误");
      return;
    }
    const data = form.value;
    if (data.isIconMenu) {
      data.type = "2";
    } else {
      data.type = data.parentId == 0 ? "1" : "3";
    }

    const actionUrl = "sys/sysMenu/" + (data.id ? "edit" : "add");
    this.fetchService
      .post(actionUrl, data)
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(res => {
        this.message.success("请刷新页面，显示菜单修改结果");
        this.hasChanges = false;
        this.updateMenu();
      });
  }

  updateIconMenuCheckStatus(parentId, icon) {
    const enabled = parentId == "0" && icon != "";
    if (enabled) {
      this.form.controls["isIconMenu"].enable();
    } else {
      this.form.controls["isIconMenu"].setValue(false);
      this.form.controls["isIconMenu"].disable();
    }
  }

  updateMenu() {
    this.fetchService.post<any>("sys/sysUser/curr", {}).subscribe(res => {
      localStorage.setItem("menuList", JSON.stringify(res.menuList));
      this.authService.updateMenuData(res.menuList);
    });
    this.fetchMenuList(true);
  }
}

interface TreeItem {
  id: any;
  key: string;
  title: string;
  name: string;
  parentIds: string;
  href?: string;
  icon?: string;
  sort?: number;
  type?: string;
  [key: string]: any;
}

interface TreePath {
  id: string;
  namePath: string;
}
